home *** CD-ROM | disk | FTP | other *** search
Text File | 2000-06-23 | 34.7 KB | 1,169 lines |
- //////////
- //
- // File: SoundSnippets.c
- //
- // Contains: Code snippets showing how to perform a few typical sound-related operations.
- //
- // Written by: Tim Monroe
- // Some routines based on existing code by Jim Reekes and Kip Olson.
- //
- // Copyright: © 1998 by Apple Computer, Inc., all rights reserved.
- //
- // Change History (most recent first):
- //
- // <7> 02/03/99 rtm minor tweaks based on AudioConvert.c sample code
- // <6> 02/03/99 rtm reworked prompt and filename handling to remove "\p" sequences
- // <5> 06/25/98 rtm added SndSnip_HasSoundManager3_1; modified the function
- // SndSnip_PromptUserForDiskFileAndSaveCompressed to compress a
- // file in 40K chunks
- // <4> 06/22/98 rtm added SndSnip_GetAudioSettings and SndSnip_ConvertWAVEFormats;
- // added SndSnip_PromptUserForAudioFileAndCompress and
- // SndSnip_PromptUserForDiskFileAndSaveCompressed, which illustrate
- // both the standard sound compression dialog component and the
- // sound converter routines
- // <3> 05/29/98 rtm added SndSnip_GetHardwareSettings, SndSnip_CheckVersionNumber,
- // SndSnip_GetVolume, and SndSnip_SetVolume
- // <2> 04/24/98 rtm got bufferCmd double-buffering working
- // <1> 04/17/98 rtm first file
- //
- // This sample code illustrates how to perform some common sound-related operations,
- // such as saving a movie's sound track into a separate file or playing a continuous sound using
- // the bufferCmd sound command. This is not really a library of utilities, but more a grab-bag
- // of "how-to" recipes. Here's a partial list of what's illustrated here:
- //
- // *Save a sound-only QuickTime movie as a WAVE file.
- // *Save a sound-only QuickTime movie as a file whose type the user selects.
- // *Save a sound track in a QuickTime movie as a file whose type the user selects.
- // *Create a handle that contains the first sound track in a QuickTime movie.
- // *Open and play a WAVE file using the QuickTime API.
- // *Set the volume level of a sound track in a QuickTime movie.
- // *Use the bufferCmd sound command to continuously play a large buffer of audio data.
- // *Get the current hardware settings.
- // *Get the settings for a sound track in a QuickTime movie.
- // *Get and set the current left and right volumes of a sound channel.
- // *Let the user select an audio file and select its compression settings; then compress it.
- //
- // NOTES:
- //
- // *** (1) ***
- // The function SndSnip_PromptUserForAudioFileAndCompress uses the standard sound compression dialog routines
- // to elicit compression/conversion settings from the user. These routines were based on the standard image
- // compression dialog routines. You can use modal-dialog filter functions and hook functions with the sound
- // routines in the same way that you use them with the image routines; this, however, is not illustrated here.
- // See the code snippet QTStdCompr for sample code that does illustrate these features of the standard
- // compression dialog routines.
- //
- // *** (2) ***
- // The function SndSnip_PromptUserForDiskFileAndSaveCompressed uses the sound converter routines (such as
- // SoundConverterConvertBuffer) to compress audio data. These routines were introduced in Sound Manager 3.2.
- // If you want to run in earlier Sound Manager versions, you'll need to replace this conversion method with
- // some other method. The method illustrated here is based on code in the file SoundConvert.c by Andrew Wulf,
- // Apple Developer Technical Support.
- //
- //////////
-
- #include "SoundSnippets.h"
- #include "QTUtilities.h"
-
-
- // global variables
- SoundHeader gSndHeader1;
- SoundHeader gSndHeader2;
- Boolean gCurrChunkDirty = false;
- short gCurrChunkIndex;
- SoundHeaderPtr gCurrChunkHeader;
- SndChannelPtr gCurrChannel;
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Sound movie conversion routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_SaveSoundMovieAsWAVEFile
- // Save a sound-only QuickTime movie as a WAVE file.
- //
- //////////
-
- void SndSnip_SaveSoundMovieAsWAVEFile (Movie theMovie)
- {
- StandardFileReply myReply;
- StringPtr myPrompt = QTUtils_ConvertCToPascalString(kSaveSoundPrompt);
- StringPtr myFileName = QTUtils_ConvertCToPascalString(kSaveSoundWaveName);
-
- // have the user select the name and location of the new WAVE file
- StandardPutFile(myPrompt, myFileName, &myReply);
- if (!myReply.sfGood)
- return;
-
- // use the default progress procedure, if any
- SetMovieProgressProc(theMovie, (MovieProgressUPP)-1L, 0);
-
- // export the movie into a file
- ConvertMovieToFile( theMovie, // the movie to convert
- NULL, // all tracks in the movie
- &myReply.sfFile, // the output file
- kQTFileTypeWave, // the output file type
- FOUR_CHAR_CODE('TVOD'), // the output file creator
- smSystemScript, // the script
- NULL, // no resource ID to be returned
- 0L, // no flags
- NULL); // no specific component
-
- free(myPrompt);
- free(myFileName);
- }
-
-
- //////////
- //
- // SndSnip_SaveSoundMovieAsAnyTypeFile
- // Save a sound-only QuickTime movie as a file whose type the user selects.
- //
- //////////
-
- void SndSnip_SaveSoundMovieAsAnyTypeFile (Movie theMovie)
- {
- StandardFileReply myReply;
- StringPtr myPrompt = QTUtils_ConvertCToPascalString(kSaveSoundPrompt);
- StringPtr myFileName = QTUtils_ConvertCToPascalString(kSaveSoundFileName);
-
- // have the user select the name and location of the new file
- StandardPutFile(myPrompt, myFileName, &myReply);
- if (!myReply.sfGood)
- return;
-
- // use the default progress procedure, if any
- SetMovieProgressProc(theMovie, (MovieProgressUPP)-1L, 0);
-
- // export the movie into a file; since the flag showUserSettingsDialog is set,
- // the user gets to select the audio format of the saved audio data
- ConvertMovieToFile( theMovie, // the movie to convert
- NULL, // all tracks in the movie
- &myReply.sfFile, // the output file
- 0L, // the output file type
- FOUR_CHAR_CODE('TVOD'), // the output file creator
- smSystemScript, // the script
- NULL, // no resource ID to be returned
- createMovieFileDeleteCurFile | movieToFileOnlyExport | showUserSettingsDialog,
- NULL); // no specific component
-
- free(myPrompt);
- free(myFileName);
-
- }
-
-
- //////////
- //
- // SndSnip_SaveSoundTrackAsAnyTypeFile
- // Save the first sound track in a QuickTime movie as a file whose type the user selects.
- //
- //////////
-
- void SndSnip_SaveSoundTrackAsAnyTypeFile (Movie theMovie)
- {
- StandardFileReply myReply;
- Track myTrack = NULL;
- StringPtr myPrompt = QTUtils_ConvertCToPascalString(kSaveSoundPrompt);
- StringPtr myFileName = QTUtils_ConvertCToPascalString(kSaveSoundFileName);
-
- // find the first sound track in the specified movie
- myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
- if (myTrack == NULL)
- return;
-
- // have the user select the name and location of the new file
- StandardPutFile(myPrompt, myFileName, &myReply);
- if (!myReply.sfGood)
- return;
-
- // use the default progress procedure, if any
- SetMovieProgressProc(theMovie, (MovieProgressUPP)-1L, 0);
-
- // export the specified track into a file; since the flag showUserSettingsDialog is set,
- // the user gets to select the audio format of the saved audio data
- ConvertMovieToFile( theMovie, // the movie to convert
- myTrack, // save only the specified track
- &myReply.sfFile, // the output file
- 0L, // the output file type
- FOUR_CHAR_CODE('TVOD'), // the output file creator
- smSystemScript, // the script
- NULL, // no resource ID to be returned
- createMovieFileDeleteCurFile | movieToFileOnlyExport | showUserSettingsDialog,
- NULL); // no specific component
-
- free(myPrompt);
- free(myFileName);
- }
-
-
- //////////
- //
- // SndSnip_ExtractSoundTrackIntoHandle
- // Create a handle that contains the first sound track in a QuickTime movie.
- //
- // NOTE: To create a handle that contains ALL the sound tracks in the movie
- // mixed together, pass NULL instead of myTrack to PutMovieIntoTypedHandle.
- //
- //////////
-
- void SndSnip_ExtractSoundTrackIntoHandle (Movie theMovie)
- {
- Track myTrack = NULL;
- Handle myHandle = NULL;
- OSErr myErr = noErr;
-
- // find the first sound track in the specified movie
- myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
- if (myTrack == NULL)
- goto bail;
-
- // create an empty handle; this will be resized by PutMovieIntoTypedHandle
- myHandle = NewHandle(0);
- if (myHandle == NULL)
- goto bail;
-
- // use the default progress procedure, if any
- SetMovieProgressProc(theMovie, (MovieProgressUPP)-1L, 0);
-
- // extract the sound track and put it into the handle
- myErr = PutMovieIntoTypedHandle(
- theMovie, // the movie to convert
- myTrack, // save only the specified track
- soundListRsrc, // make it a sound resource handle
- myHandle, // the handle into which to put the audio data
- 0, // start time
- GetTrackDuration(myTrack), // ending time
- 0L, // flags
- NULL); // no specific component
- if (myErr != noErr)
- goto bail;
-
- // to prove we really did create the handle, play it
- SndPlay(NULL, (SndListHandle)myHandle, false);
-
- bail:
- if (myHandle != NULL)
- DisposeHandle(myHandle);
- }
-
-
- //////////
- //
- // SndSnip_PlayWAVEFileWithQuickTime
- // Open and play a WAVE file using the QuickTime API.
- //
- //////////
-
- void SndSnip_PlayWAVEFileWithQuickTime (void)
- {
- StandardFileReply myReply;
- SFTypeList myTypeList = {kQTFileTypeWave, 0, 0, 0};
- short myRefNum;
-
- // elicit a file from the user
- StandardGetFile(NULL, 1, myTypeList, &myReply);
- if (myReply.sfGood) {
- Movie myMovie;
-
- OpenMovieFile(&myReply.sfFile, &myRefNum, fsRdPerm);
- NewMovieFromFile(&myMovie, myRefNum, NULL, (StringPtr)NULL, newMovieActive, NULL);
- if (myRefNum != 0)
- CloseMovieFile(myRefNum);
-
- // play the movie once thru
- StartMovie(myMovie);
- while (!IsMovieDone(myMovie))
- MoviesTask(myMovie, 0);
- DisposeMovie(myMovie);
- }
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Volume routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_SetVolumeOfSoundTrack
- // Set the volume level of the first sound track in a QuickTime movie.
- //
- // The range for the theVolume parameter is 0 (no volume) to 256 (full volume).
- // You can also pass negative values (e.g., -128). No sound is produced for negative
- // values, but they are useful for maintaining the absolute value of a volume.
- //
- //////////
-
- void SndSnip_SetVolumeOfSoundTrack (Movie theMovie, short theVolume)
- {
- Track myTrack = NULL;
-
- // find the first sound track in the specified movie
- myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
- if (myTrack == NULL)
- return;
-
- // set the volume of the track
- SetTrackVolume(myTrack, theVolume);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Double-buffering routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_PlaySoundResourceUsingBufferCmds
- // Use the bufferCmd sound command to continuously play a large buffer of audio data.
- //
- // NOTE: This routine exists solely to illustrate one way to use bufferCmd sound commands
- // to play a buffer of audio data continuously; here, we read the audio data from a resource
- // and then hand chunks of it to the Sound Manager using bufferCmds. OF COURSE we could have
- // played the entire buffer in one fell swoop by calling SndPlay. The idea is that a real
- // application would read the audio data from disk in bite-sized chunks and use the techniques
- // illustrated here to play that data.
- //
- //////////
-
- OSErr SndSnip_PlaySoundResourceUsingBufferCmds (void)
- {
- Handle myHandle = NULL;
- SoundComponentData myResourceInfo;
- unsigned long myNumFrames;
- unsigned long myOffset;
- Ptr myPtr = NULL;
- Size mySize;
- long myFreq;
- SndChannelPtr mySndChannel = NULL;
- SndCallBackUPP mySndCallBackProc;
- unsigned long myBufferSize; // the size of the buffer we pass to each bufferCmd command
- OSErr myErr = memFullErr;
-
- // get the resource data; we assume this resource contains sampled sound data
- myHandle = GetResource(soundListRsrc, kSampleResourceID);
- if (myHandle == NULL)
- goto bail;
-
- // get info from the sound resource header
- myErr = ParseSndHeader((SndListHandle)myHandle, &myResourceInfo, &myNumFrames, &myOffset);
- if (myErr != noErr)
- goto bail;
-
- // get the base frequency from the sampled sound header
- myFreq = SndSnip_GetSndBaseFrequency(myHandle);
-
- // lock the handle, so we can use a pointer to cruise thru the sound data
- HLockHi(myHandle);
-
- myPtr = *myHandle + myOffset;
- mySize = GetHandleSize(myHandle) - myOffset;
- myBufferSize = mySize / kNumberOfBufferChunks;
-
- // allocate a routine descriptor for our sound callback routine
- mySndCallBackProc = NewSndCallBackProc(SndSnip_CallbackProc);
-
- // create storage for a new sound channel
- mySndChannel = (SndChannelPtr)NewPtrClear(sizeof(SndChannel));
- if (mySndChannel == NULL)
- goto bail;
-
- // set the number of commands in the sound channel queue;
- // pass the application's A5 value in the userInfo field
- mySndChannel->qLength = kNumberOfCmdsInQueue;
- #if TARGET_OS_MAC
- mySndChannel->userInfo = SetCurrentA5();
- #endif
-
- // create the sound channel
- myErr = SndNewChannel(&mySndChannel, sampledSynth, initMono, mySndCallBackProc);
- if (myErr != noErr) {
- DisposePtr((Ptr)mySndChannel);
- goto bail;
- }
-
- // the basic idea is this: fill two buffers with data and pass them to the Sound Manager
- // using the bufferCmd sound command; each bufferCmd is immediately followed in the queue
- // by a callBackCmd sound command; a callBackCmd triggers the _CheckBuffers routine, which
- // installs another buffer of data and an associated callBackCmd
-
- // configure the first sound header
- gSndHeader1.samplePtr = myPtr;
- gSndHeader1.length = myBufferSize;
- gSndHeader1.sampleRate = myResourceInfo.sampleRate;
- gSndHeader1.loopStart = 0;
- gSndHeader1.loopEnd = 0;
- gSndHeader1.encode = stdSH;
- gSndHeader1.baseFrequency = myFreq;
-
- // install the first bufferCmd, to play the first chunk of the buffer
- myErr = SndSnip_InstallBufferCmd(mySndChannel, &gSndHeader1);
-
- // install the first callBackCmd
- myErr = SndSnip_InstallCallbackCmd(mySndChannel, 0, (long)&gSndHeader1);
-
- // configure the second sound header
- gSndHeader2.samplePtr = myPtr + myBufferSize;
- gSndHeader2.length = myBufferSize;
- gSndHeader2.sampleRate = myResourceInfo.sampleRate;
- gSndHeader2.loopStart = 0;
- gSndHeader2.loopEnd = 0;
- gSndHeader2.encode = stdSH;
- gSndHeader2.baseFrequency = myFreq;
-
- // install the second bufferCmd, to play the second chunk of the buffer
- myErr = SndSnip_InstallBufferCmd(mySndChannel, &gSndHeader2);
-
- // install the second callBackCmd
- myErr = SndSnip_InstallCallbackCmd(mySndChannel, 1, (long)&gSndHeader2);
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // SndSnip_CallbackProc
- // Handle callback messages. Keep it quick, okay?
- //
- //////////
-
- PASCAL_RTN void SndSnip_CallbackProc (SndChannelPtr theChannel, SndCommand *theCommand)
- {
- #if TARGET_OS_MAC
- long myA5;
-
- myA5 = SetA5(theChannel->userInfo);
- #endif
-
- // in this sample code, param1 of theCommand is the 0-based index of the chunk of the buffer
- // that just finished playing, and param2 is a pointer to the sound header for that chunk
- gCurrChunkDirty = true;
- gCurrChunkIndex = theCommand->param1;
- gCurrChunkHeader = (SoundHeaderPtr)(theCommand->param2);
- gCurrChannel = theChannel;
-
- #if TARGET_OS_MAC
- myA5 = SetA5(myA5);
- #endif
- }
-
-
- //////////
- //
- // SndSnip_CheckBuffers
- // Handle callback messages.
- //
- // This function needs to be called periodically. On MacOS, you could call this function
- // every time thru your event loop. On Windows, you'll need to use a different strategy;
- // for instance, you could install a timer that is called often enough that the bufferCmd
- // gets installed before the currently-playing buffer is exhausted.
- //
- //////////
-
- void SndSnip_CheckBuffers (void)
- {
- if (gCurrChunkDirty) {
-
- // install next buffer of data, if there is one
- if (gCurrChunkIndex < (kNumberOfBufferChunks - 2)) {
-
- gCurrChunkHeader->samplePtr = gCurrChunkHeader->samplePtr + (2 * (gCurrChunkHeader->length));
-
- // install a bufferCmd command, to play the next buffer of data
- SndSnip_InstallBufferCmd(gCurrChannel, gCurrChunkHeader);
-
- // install a callBackCmd command, to be called when this buffer is finished playing
- SndSnip_InstallCallbackCmd(gCurrChannel, gCurrChunkIndex + 2, (long)gCurrChunkHeader);
- }
- }
-
- gCurrChunkDirty = false;
- }
-
-
- //////////
- //
- // SndSnip_InstallBufferCmd
- // Install a bufferCmd sound command to play the specified buffer of data.
- //
- //////////
-
- static OSErr SndSnip_InstallBufferCmd (SndChannelPtr theChannel, SoundHeaderPtr theHeaderPtr)
- {
- SndCommand mySndCommand;
-
- mySndCommand.cmd = bufferCmd;
- mySndCommand.param1 = 0;
- mySndCommand.param2 = (long)theHeaderPtr;
- return(SndDoCommand(theChannel, &mySndCommand, kWait));
- }
-
-
- //////////
- //
- // SndSnip_InstallCallbackCmd
- // Install a callBackCmd sound command.
- //
- //////////
-
- static OSErr SndSnip_InstallCallbackCmd (SndChannelPtr theChannel, short theParam1, long theParam2)
- {
- SndCommand mySndCommand;
-
- mySndCommand.cmd = callBackCmd;
- mySndCommand.param1 = theParam1;
- mySndCommand.param2 = theParam2;
- return(SndDoCommand(theChannel, &mySndCommand, kWait));
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Sample sound information routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_GetSoundHeader
- // Returns a pointer to the sound header in a sampled sound resource.
- //
- //////////
-
- SoundHeaderPtr SndSnip_GetSoundHeader (Handle theSndHandle)
- {
- SoundHeaderPtr mySndHeader = NULL;
- long myOffset = 0;
- OSErr myErr = noErr;
-
- myErr = GetSoundHeaderOffset((SndListHandle)theSndHandle, &myOffset);
- if (myErr == noErr)
- mySndHeader = (SoundHeaderPtr)((long)*theSndHandle + myOffset);
-
- return(mySndHeader);
- }
-
-
- //////////
- //
- // SndSnip_GetSndBaseFrequency
- // Returns the base frequency of a sampled sound.
- //
- //////////
-
- long SndSnip_GetSndBaseFrequency (Handle theSndHandle)
- {
- SoundHeaderPtr mySndHeader;
- long myBaseFreq = kMiddleC; // a reasonable default
-
- mySndHeader = SndSnip_GetSoundHeader(theSndHandle);
- if (mySndHeader != NULL)
- myBaseFreq = mySndHeader->baseFrequency;
-
- return(myBaseFreq);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Settings routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_GetHardwareSettings
- // Get the current hardware settings.
- //
- // Based on the function GetHardwareSettings by Kip Olson (develop, issue 24).
- //
- //////////
-
- OSErr SndSnip_GetHardwareSettings (SndChannelPtr theChannel, SoundComponentData *theInfo)
- {
- NumVersion myVersion;
- OSErr myErr = noErr;
-
- // SndGetInfo is available only in Sound Manager 3.1 or later,
- // so check for an appropriate Sound Manager version
- myVersion = SndSoundManagerVersion();
-
- if (!SndSnip_CheckVersionNumber(&myVersion, 3, 1, 0))
- goto bail;
-
- myErr = SndGetInfo(theChannel, siNumberChannels, &theInfo->numChannels);
- if (myErr != noErr)
- goto bail;
-
- myErr = SndGetInfo(theChannel, siSampleRate, &theInfo->sampleRate);
- if (myErr != noErr)
- goto bail;
-
- myErr = SndGetInfo(theChannel, siSampleSize, &theInfo->sampleSize);
- if (myErr != noErr)
- goto bail;
-
- if (theInfo->sampleSize == 8)
- theInfo->format = kOffsetBinary;
- else
- theInfo->format = kTwosComplement;
-
- bail:
- return(myErr);
- }
-
-
- //////////
- //
- // SndSnip_GetAudioSettings
- // Get the settings for the first audio track in the specified movie.
- //
- //////////
-
- OSErr SndSnip_GetAudioSettings (Movie theMovie, SoundComponentData *theInfo)
- {
- Track myTrack = NULL;
- Media myMedia = NULL;
- SoundDescriptionHandle myDesc = NULL;
- OSErr myErr = paramErr;
-
- // get the first sound track in the specified movie
- myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
- if (myTrack == NULL)
- goto bail;
-
- myMedia = GetTrackMedia(myTrack);
- if (myMedia == NULL)
- goto bail;
-
- myDesc = (SoundDescriptionHandle)NewHandle(0);
- if (myDesc == NULL)
- goto bail;
-
- GetMediaSampleDescription(myMedia, 1, (SampleDescriptionHandle)myDesc);
- if (GetHandleSize((Handle)myDesc) == 0)
- goto bail;
-
- theInfo->numChannels = (**myDesc).numChannels;
- theInfo->sampleRate = (**myDesc).sampleRate;
- theInfo->sampleSize = (**myDesc).sampleSize;
- theInfo->format = (**myDesc).dataFormat;
-
- myErr = noErr;
-
- bail:
-
- if (myDesc != NULL)
- DisposeHandle((Handle)myDesc);
-
- return(myErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Sound information routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_HasSoundManager3_1
- // Returns true if the installed version of the Sound Manager is at least 3.1.
- //
- //////////
-
- Boolean SndSnip_HasSoundManager3_1 (void)
- {
- NumVersionVariant myVersion;
-
- myVersion.parts = SndSoundManagerVersion();
- return(myVersion.whole >= 0x03100000);
- }
-
-
- //////////
- //
- // SndSnip_CheckVersionNumber
- // Returns true if the given version number is compatible with
- // (that is, not older than) version theMajor.theMinor.theBug.
- //
- //////////
-
- Boolean SndSnip_CheckVersionNumber (
- const NumVersion *theVersion,
- UInt8 theMajor,
- UInt8 theMinor,
- UInt8 theBug)
- {
- if (theVersion->majorRev != theMajor)
- return(theVersion->majorRev > theMajor);
- else
- return(theVersion->minorAndBugRev >= theMinor << 4 | theBug);
- }
-
-
- //////////
- //
- // SndSnip_GetVolume
- // Get the current left and right volumes of a sound channel.
- //
- // Based on the function GetVolume by Kip Olson (develop, issue 24).
- //
- //////////
-
- OSErr SndSnip_GetVolume (SndChannelPtr theChannel, unsigned short *theLeftVol, unsigned short *theRightVol)
- {
- SndCommand mySndCommand;
- unsigned long myVolume;
- OSErr myErr = noErr;
-
- // getVolumeCmd is available only in Sound Manager version 3.0 and later;
- // you might want to check for a correct version here
-
- mySndCommand.cmd = getVolumeCmd;
- mySndCommand.param1 = 0;
- mySndCommand.param2 = (long)&myVolume;
- myErr = SndDoImmediate(theChannel, &mySndCommand);
-
- if (myErr == noErr) {
- *theLeftVol = myVolume & 0x0000ffff;
- *theRightVol = myVolume >> 16;
- }
-
- return(myErr);
- }
-
-
- //////////
- //
- // SndSnip_SetVolume
- // Set the left and right volumes of a sound channel.
- //
- // Based on the function SetVolume by Kip Olson (develop, issue 24).
- //
- //////////
-
- OSErr SndSnip_SetVolume (SndChannelPtr theChannel, unsigned short theLeftVol, unsigned short theRightVol)
- {
- SndCommand mySndCommand;
- OSErr myErr = noErr;
-
- // volumeCmd is available only in Sound Manager version 3.0 and later;
- // you might want to check for a correct version here
-
- mySndCommand.cmd = volumeCmd;
- mySndCommand.param1 = 0;
- mySndCommand.param2 = (theRightVol << 16) | theLeftVol;
-
- myErr = SndDoImmediate(theChannel, &mySndCommand);
- return(myErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Movie export component routines.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_ConvertWAVEFormats
- // Convert an 8-bit, 22 kHz WAVE file to a 16-bit, 22 kHz IMAPCM WAVE file.
- //
- //////////
-
- OSErr SndSnip_ConvertWAVEFormats (Movie theMovie, FSSpec *theFile)
- {
- ComponentInstance myComponent = NULL;
- SoundDescriptionHandle myDesc = NULL;
- ComponentResult myErr = badComponentType;
-
- // open a movie export component
- myComponent = OpenDefaultComponent(MovieExportType, kQTFileTypeWave);
- if (myComponent == NULL)
- goto bail;
-
- // create and fill in a sound description
- myDesc = (SoundDescriptionHandle)NewHandleClear(sizeof(SoundDescription));
- if (myDesc == NULL) {
- myErr = MemError();
- goto bail;
- }
-
- (**myDesc).descSize = sizeof(SoundDescription);
- (**myDesc).sampleSize = 16;
- (**myDesc).sampleRate = rate22050hz;
- (**myDesc).dataFormat = k16BitLittleEndianFormat;
-
- // tell the export component to use the specified audio characteristics
- myErr = MovieExportSetSampleDescription(myComponent, (SampleDescriptionHandle)myDesc, SoundMediaType);
- if (myErr != noErr)
- goto bail;
-
- // export the movie into a file
- myErr = ConvertMovieToFile(
- theMovie, // the movie to convert
- NULL, // all tracks in the movie
- theFile, // the output file
- kQTFileTypeWave, // the output file type
- FOUR_CHAR_CODE('TVOD'), // the output file creator
- smSystemScript, // the script
- NULL, // no resource ID to be returned
- 0L, // no flags
- myComponent); // the export component
-
- bail:
- // dispose of any storage we allocated
- if (myComponent != NULL)
- CloseComponent(myComponent);
-
- if (myDesc != NULL)
- DisposeHandle((Handle)myDesc);
-
- return((OSErr)myErr);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Standard sound compression dialog routines.
- //
- // These routines illustrate how to use QuickTime's standard sound compression dialog routines
- // to get compression settings from the user and to compress a sound using those settings. See
- // Chapter 20 of QuickTime 3 Reference for information on the standard sound compression dialog
- // routines.
- //
- // These routines show how to display the standard sound compression dialog box directly; you can
- // also display the dialog box indirectly by using ConvertMovieToFile with the showUserSettingsDialog
- // flag set; see SndSnip_SaveSoundTrackAsAnyTypeFile above for an example.
- //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- //////////
- //
- // SndSnip_PromptUserForAudioFileAndCompress
- // Let the user select an audio file and select its compression settings; then compress it.
- //
- //////////
-
- void SndSnip_PromptUserForAudioFileAndCompress (void)
- {
- SFTypeList myTypeList;
- StandardFileReply myReply;
- short myRefNum = 0;
- SoundComponentData mySrcInfo;
- SoundComponentData myDstInfo;
- unsigned long myNumFrames = 0;
- unsigned long myDataOffset = 0;
- ComponentInstance myComponent = NULL;
- OSErr myErr = noErr;
-
- //////////
- //
- // have the user select an AIFF or AIFF-C file
- //
- //////////
-
- myTypeList[0] = kQTFileTypeAIFF;
- myTypeList[1] = kQTFileTypeAIFC;
-
- StandardGetFilePreview(NULL, 2, myTypeList, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- //////////
- //
- // open the selected sound file and get the characteristics of the sound
- //
- //////////
-
- myErr = FSpOpenDF(&myReply.sfFile, fsCurPerm, &myRefNum);
- if (myErr != noErr)
- goto bail;
-
- myErr = ParseAIFFHeader(myRefNum, &mySrcInfo, &myNumFrames, &myDataOffset);
- if (myErr != noErr)
- goto bail;
-
- // zero out fields we're not interested in
- mySrcInfo.flags = 0L;
- mySrcInfo.sampleCount = 0L;
- mySrcInfo.buffer = NULL;
- mySrcInfo.reserved = 0L;
-
- //////////
- //
- // display the standard sound compression dialog box
- //
- //////////
-
- // open the standard compression dialog component
- myComponent = OpenDefaultComponent(StandardCompressionType, StandardCompressionSubTypeSound);
- if (myComponent == NULL)
- goto bail;
-
- // set the initial values for the dialog box, using the current characteristics of the selected sound
- SCSetInfo(myComponent, scSoundSampleRateType, &(mySrcInfo.sampleRate));
- SCSetInfo(myComponent, scSoundSampleSizeType, &(mySrcInfo.sampleSize));
- SCSetInfo(myComponent, scSoundChannelCountType, &(mySrcInfo.numChannels));
- SCSetInfo(myComponent, scSoundCompressionType, &(mySrcInfo.format));
-
- // request sound compression settings from the user; in other words, put up the dialog box
- // (don't let "Image" in the name here fool you: it's just a relic from the fact that the
- // sound compression dialog routines were based on the existing image compression dialog routines)
- myErr = SCRequestImageSettings(myComponent);
- if (myErr == userCanceledErr)
- goto bail;
-
- //////////
- //
- // retrieve the compression/conversion settings selected by the user
- //
- //////////
-
- SCGetInfo(myComponent, scSoundSampleRateType, &(myDstInfo.sampleRate));
- SCGetInfo(myComponent, scSoundSampleSizeType, &(myDstInfo.sampleSize));
- SCGetInfo(myComponent, scSoundChannelCountType, &(myDstInfo.numChannels));
- SCGetInfo(myComponent, scSoundCompressionType, &(myDstInfo.format));
-
- // any non-compressed format appears as 'raw ', which is not what the Sound Manager expects
- if (myDstInfo.format == k8BitOffsetBinaryFormat)
- myDstInfo.format = kSoundNotCompressed;
-
- // zero out fields we're not interested in
- myDstInfo.flags = 0L;
- myDstInfo.sampleCount = 0L;
- myDstInfo.buffer = NULL;
- myDstInfo.reserved = 0L;
-
- //////////
- //
- // save the compressed sound in a new file
- //
- //////////
-
- SndSnip_PromptUserForDiskFileAndSaveCompressed(myRefNum, &mySrcInfo, &myDstInfo, myDataOffset, myNumFrames);
-
- bail:
-
- if (myComponent != NULL)
- CloseComponent(myComponent);
-
- if (myRefNum != 0)
- FSClose(myRefNum);
- }
-
-
- //////////
- //
- // SndSnip_PromptUserForDiskFileAndSaveCompressed
- // Let the user select a new disk file, then convert the specified audio data into that file.
- //
- // This routine uses the Sound Converter routines introduced in Sound Manager 3.2.
- //
- //////////
-
- void SndSnip_PromptUserForDiskFileAndSaveCompressed (short theSrcRefNum, SoundComponentData *theSrcInfo, SoundComponentData *theDstInfo, unsigned long theSrcDataOffset, unsigned long theSrcNumFrames)
- {
- StandardFileReply myReply;
- SoundConverter myConverter = NULL;
- unsigned long myNumInputFrames, myNumInputBytes, myNumOutputBytes;
- Ptr myInputBuffer = NULL;
- Ptr myOutputBuffer = NULL;
- short myDstRefNum = 0;
- StringPtr myPrompt = QTUtils_ConvertCToPascalString(kSaveSoundPrompt);
- StringPtr myFileName = QTUtils_ConvertCToPascalString(kSaveSoundFileName);
- OSErr myErr = noErr;
-
- //////////
- //
- // prompt the user for a file to put the compressed sound into
- //
- //////////
-
- StandardPutFile(myPrompt, myFileName, &myReply);
- if (!myReply.sfGood)
- goto bail;
-
- if (myReply.sfReplacing) {
- myErr = FSpDelete(&myReply.sfFile);
- if (myErr != noErr)
- goto bail;
- }
-
- //////////
- //
- // open a sound converter
- //
- //////////
-
- // perform in non-real time for best quality
- theDstInfo->flags |= kNoRealtimeProcessing;
-
- myErr = SoundConverterOpen(theSrcInfo, theDstInfo, &myConverter);
- if (myErr != noErr)
- goto bail;
-
- myErr = SoundConverterGetBufferSizes(myConverter, kNumberOfTargetBytes, &myNumInputFrames, &myNumInputBytes, &myNumOutputBytes);
- if (myErr != noErr)
- goto bail;
-
- //////////
- //
- // convert the sound to the desired output format
- //
- //////////
-
- // create the input and output buffers
- myInputBuffer = NewPtrClear(myNumInputBytes);
- if (myInputBuffer == NULL)
- goto bail;
-
- myOutputBuffer = NewPtrClear(myNumOutputBytes);
- if (myOutputBuffer == NULL)
- goto bail;
-
- // create and open the output file
- myErr = FSpCreate(&myReply.sfFile, FOUR_CHAR_CODE('TVOD'), kQTFileTypeAIFC, smSystemScript);
- if (myErr != noErr)
- goto bail;
-
- myErr = FSpOpenDF(&myReply.sfFile, fsRdWrPerm, &myDstRefNum);
- if (myErr != noErr)
- goto bail;
-
- SetEOF(myDstRefNum, 0L);
-
- // convert the audio data
- myErr = SoundConverterBeginConversion(myConverter);
- if (myErr == noErr) {
- long myInputFileSize = 0L;
- unsigned long myActOutputFrames = 0L;
- unsigned long myActOutputSize = 0L;
- unsigned long myAddOutputFrames = 0L;
- unsigned long myAddOutputSize = 0L;
- long myCurrentFrames = 0L;
- long myNumFramesLeft = theSrcNumFrames;
- long myBytesRead = 0L;
- long myBytesWritten = 0L;
- long myFramesWritten = 0L;
-
- // set up the input file for reading
- GetEOF(theSrcRefNum, &myInputFileSize);
-
- myErr = SetFPos(theSrcRefNum, fsFromStart, theSrcDataOffset);
- if (myErr != noErr)
- goto bail;
-
- myInputFileSize -= theSrcDataOffset;
-
- // set up a preliminary AIFF header for the output file;
- // we'll update the actual values later....
- myErr = SetupAIFFHeader(myDstRefNum,
- theDstInfo->numChannels,
- theDstInfo->sampleRate,
- theDstInfo->sampleSize,
- theDstInfo->format,
- 0L,
- 0L);
- if (myErr != noErr)
- goto bail;
-
- myCurrentFrames = myNumInputFrames;
-
- // loop through buffers of size myNumInputFrames
- while (myNumFramesLeft > 0) {
-
- // read a buffer of data from the input file
- myBytesRead = myNumInputBytes;
- myErr = FSRead(theSrcRefNum, &myBytesRead, myInputBuffer);
- if ((myErr != noErr) && (myErr != eofErr))
- goto bail;
-
- // convert the buffer
- myErr = SoundConverterConvertBuffer(myConverter,
- myInputBuffer,
- myCurrentFrames,
- myOutputBuffer,
- &myActOutputFrames,
- &myActOutputSize);
- if (myErr != noErr)
- goto bail;
-
- // write the converted data into the output file
- myErr = FSWrite(myDstRefNum, (long *)&myActOutputSize, myOutputBuffer);
- if (myErr != noErr)
- goto bail;
-
- myBytesWritten += myActOutputSize;
- myFramesWritten += myActOutputFrames;
-
- // calculate remaining frames and adjust myCurrentFrames for last buffer
- myNumFramesLeft -= myCurrentFrames;
- if (myNumFramesLeft < myNumInputFrames)
- myCurrentFrames = myNumFramesLeft;
- }
-
- // end the conversion, and see if we get back a few more bytes of data
- myErr = SoundConverterEndConversion(myConverter, myOutputBuffer, &myAddOutputFrames, &myAddOutputSize);
- if (myErr != noErr)
- goto bail;
-
- // if we got any more data, write it to disk
- if (myAddOutputFrames != 0L) {
- myErr = FSWrite(myDstRefNum, (long *)&myAddOutputSize, myOutputBuffer);
- if (myErr != noErr)
- goto bail;
- }
-
- myErr = SetFPos(myDstRefNum, fsFromStart, 0);
- if (myErr != noErr)
- goto bail;
-
- // update AIFF header
- myErr = SetupAIFFHeader(
- myDstRefNum,
- theDstInfo->numChannels,
- theDstInfo->sampleRate,
- theDstInfo->sampleSize,
- theDstInfo->format,
- myBytesWritten + myAddOutputSize,
- myFramesWritten + myAddOutputFrames);
- }
-
- bail:
-
- free(myPrompt);
- free(myFileName);
-
- if (myConverter != NULL)
- SoundConverterClose(myConverter);
-
- if (myInputBuffer != NULL)
- DisposePtr(myInputBuffer);
-
- if (myOutputBuffer != NULL)
- DisposePtr(myOutputBuffer);
-
- if (myDstRefNum != 0)
- FSClose(myDstRefNum);
-
- #if TARGET_OS_MAC
- // make sure the file data gets written out to disk
- FlushVol("\p", myReply.sfFile.vRefNum);
- #endif
- }
-